#include<cstdio>//uncle-lu
#include<cstring>
#include<queue>
#include<algorithm>
template<class T>void read(T &x)
{
	x=0;int f=0;char ch=getchar();
	while(ch<'0'||ch>'9') { f|=(ch=='-'); ch=getchar(); }
	while(ch<='9'&&ch>='0') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
	x = f ? -x : x;
	return ;
}

struct Heap_node{
	int x;
	double d;
	friend bool operator<(const Heap_node a, const Heap_node b)
	{
		return a.d > b.d;
	}
};
struct node{
	int v, next, val;
};
node edge[2010];
int head[210];
double d[210];
int n, m, cnt;

void add_edge(int x, int y, int val)
{
	edge[++cnt].v = y;
	edge[cnt].next=head[x];
	edge[cnt].val = val;
	head[x] = cnt;
	return ;
}

void dijsktra(double x)
{
	memset(d, 0x7f7f7f, sizeof(d));
	d[0] = 0;

	std::priority_queue<Heap_node>qu;
	qu.push( (Heap_node){0, 0} );

	while(!qu.empty())
	{
		Heap_node now = qu.top();
		qu.pop();

		if(now.d != d[now.x])continue;

		for(int i=head[now.x]; ~i; i=edge[i].next)
		{
			if(edge[i].val - x + d[now.x] < d[edge[i].v])
			{
				d[edge[i].v] = edge[i].val - x + d[now.x];
				qu.push( (Heap_node){edge[i].v, d[edge[i].v]} );
			}
		}
	}

	return ;
}

bool check(double x)
{
	dijsktra(x);
	if(d[n]>0)
		return false;
	else
		return true;
}

int main()
{
	read(n); read(m);

	memset(head, -1, sizeof(head));
	int u, v, w, mx_w=0;
	for(int i=1; i<=m; ++i)
	{
		read(u);read(v);read(w);
		mx_w = std::max(mx_w, w);
		add_edge(u, v, w);
	}

	add_edge(0, 1, 0);

	double left=0, right=mx_w, mid;
	while(right - left > 1e-4)
	{
		mid = (right + left)/2;
		if(check(mid))
			right = mid;
		else
			left = mid;
	}

	printf("%.3lf",left);
	return 0;
}
